package cn.tangsihai.hrm.service.impl;

import cn.tangsihai.hrm.client.CourseSearchClient;
import cn.tangsihai.hrm.config.RabbitMQConfig;
import cn.tangsihai.hrm.constant.Constants;
import cn.tangsihai.hrm.context.LoginContext;
import cn.tangsihai.hrm.doc.CourseESDoc;
import cn.tangsihai.hrm.domain.*;
import cn.tangsihai.hrm.dto.CourseAddDTO;
import cn.tangsihai.hrm.mapper.CourseDetailMapper;
import cn.tangsihai.hrm.mapper.CourseMapper;
import cn.tangsihai.hrm.mapper.CourseMarketMapper;
import cn.tangsihai.hrm.mapper.CourseTypeMapper;
import cn.tangsihai.hrm.mq.MQConsumer;
import cn.tangsihai.hrm.service.ICourseService;
import cn.tangsihai.hrm.to.EmailTo;
import cn.tangsihai.hrm.to.MessageTo;
import cn.tangsihai.hrm.to.SMSTo;
import cn.tangsihai.hrm.util.AjaxResult;
import cn.tangsihai.hrm.util.AssertUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.validation.Valid;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

import static cn.tangsihai.hrm.mq.MQConsumer.*;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author sihai.tang
 * @since 2021-11-26
 */
@Service
@Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course> implements ICourseService {
    @Autowired
    private CourseMarketMapper courseMarketMapper;
    @Autowired
    private CourseMapper courseMapper;
    @Autowired
    private CourseDetailMapper courseDetailMapper;
    @Autowired
    private CourseTypeMapper courseTypeMapper;
    @Autowired
    private CourseSearchClient searchClient;
    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * 新增课程:
     *      1.参数合理性判断 --使用JSR303
     *      2.数据重复性判断（根据情况，有的业务有）
     *      3.保存课程
     *      4.保存营销
     *      5.报保存详情
     *      6.注：据表可知，新增课程后课程父类总数需要修改
     */
    @Override
    @Transactional
    public void save(CourseAddDTO dto) {
        Course course = dto.getCourse();
        CourseDetail courseDetail = dto.getCourseDetail();
        CourseMarket courseMarket = dto.getCourseMarket();
        // 1.参数合理性判断 --使用JSR303
        // 2.数据重复性判断（根据情况，有的业务有）
        Course courseFromMySQL = courseMapper.selectByName(course.getName());
        AssertUtil.isNull(courseFromMySQL, "已存在该课程，请重新添加");

        // 3.保存课程
        // 从token中拿到登录对象的信息，信息就包含了机构id，机构名字等
        Login loginFromToken = LoginContext.getLogin();
        // 为空，没有登录
        AssertUtil.isNotNull(loginFromToken, "请登录");
        Course courseFromPareper = initCourse(course, loginFromToken);
        courseMapper.insert(courseFromPareper);
        AssertUtil.isNotEmpty(courseFromPareper.getId().toString(), "保存失败");

        // 4.保存营销
        CourseMarket courseMarketFromPareper = initCourseMarket(courseMarket, courseFromPareper.getId());
        courseMarketMapper.insert(courseMarketFromPareper);

        // 5.报保存详情
        CourseDetail courseDetailFromPareper = initCourseDetail(courseDetail, courseFromPareper.getId());
        courseDetailMapper.insert(courseDetailFromPareper);

        // 6.注：据表可知，新增课程后课程父类总数需要修改
        CourseType courseType = courseTypeMapper.selectById(course.getCourseTypeId());
        AssertUtil.isNotNull(courseType, "添加失败，请联系管理员");
        String[] typeIds = courseType.getPath().split("\\.");
        courseTypeMapper.batchUpdate(1, typeIds);
    }
    // 准备数据
    private CourseDetail initCourseDetail(CourseDetail courseDetail, Long id) {
        courseDetail.setId(id);
        return courseDetail;
    }

    private CourseMarket initCourseMarket(CourseMarket courseMarket, Long id) {
        courseMarket.setId(id);
        return courseMarket;
    }

    private Course initCourse(Course course, Login loginFromToken) {
        course.setStatus(Constants.Course.COURSE_STATUS_OFFLINE);
        // 机构id
        course.setTenantId(loginFromToken.getTenantId());
        // 机构名字
        course.setTenantName(loginFromToken.getTenantName());
        course.setUserId(loginFromToken.getId());
        course.setUserName(loginFromToken.getUsername());
        course.setSaleCount(0);
        course.setViewCount(0);
        course.setCommentCount(0);
        return course;
    }

    /**
     * 上线课程业务：
     *      1.根据id查询课程
     *      2.判断课程状态为下线
     *      3.修改课程状态为上线
     *      4.把课程保存到ES中
     * @param id
     */
    @Override
    @Transactional
    public void onLineCourse(Long id) {
        // 1.根据id查询课程
        Course course = courseMapper.selectById(id);
        CourseMarket courseMarket = courseMarketMapper.selectById(id);
        CourseDetail courseDetail = courseDetailMapper.selectById(id);
        AssertUtil.isNotNull(course, "该课程不存在");

        // 2.判断课程状态为下线
        Integer status = course.getStatus();
        AssertUtil.isOffline(status, "该课程已上线");

        // 3.修改课程状态为上线
        course.setStatus(Constants.Course.COURSE_STATUS_ONLINE);
        courseMapper.updateById(course);
        // 4.调用检索服务的feign接口，把课程保存到ES中
        // 注：调用其他服务的feign：此服务yml开启Hystrix熔断，此服务启动类开启feign扫描注解
        CourseESDoc esDoc = new CourseESDoc();
        BeanUtils.copyProperties(courseMarket, esDoc);
        BeanUtils.copyProperties(courseDetail, esDoc);
        BeanUtils.copyProperties(course, esDoc);
        esDoc.setOnlineTime(new Date());
        esDoc.setChargeName(courseMarket.getCharge() == 0 ? "免费" : "收费");
        esDoc.setCourseTypeId(course.getCourseTypeId());
        // 4.调用检索服务的feign接口
        searchClient.addCourseToES(esDoc);

        // 上线后发送消息
        sendMessage(course);
    }

    /**
     * 下线课程业务：
     *      1.根据id查询课程
     *      2.判断课程状态为上线
     *      3.再数据库中修改课程状态为下线
     *      4.删除ES索引中对应id的课程
     * @param id
     */
    @Override
    public void offLineCourse(Long id) {
        AssertUtil.isNotEmpty(id.toString(), "请选择需要下线的课程");

        // 1.根据id查询课程
        Course course = courseMapper.selectById(id);
        AssertUtil.isNotNull(course, "无该课程或该课程已下线");

        // 2.判断课程状态为上线
        Integer status = course.getStatus();
        AssertUtil.isOnline(status, "该课程已下线");

        // 3.再数据库中修改课程状态为下线
        course.setStatus(Constants.Course.COURSE_STATUS_OFFLINE);
        courseMapper.updateById(course);

        // 4.删除ES索引中对应id的课程
        searchClient.deleteCourseFromES(id);
    }

    // 从yml配置中拉取信息
    @Value("${message.send.contents.smsContent}")
    private String smsContent;
    @Value("${message.send.contents.emailContent}")
    private String emailContent;
    @Value("${message.send.contents.messageContent}")
    private String messageContent;

    // 发送消息
    public void sendMessage(Course course){
        smsContent = String.format(smsContent, course.getName());
        emailContent = String.format(emailContent, course.getName());
        messageContent = String.format(messageContent, course.getName());
        // 发送短信
        rabbitTemplate.convertAndSend(MQConsumer.EXCHANGE_NAME0, "course.sms", new SMSTo(Arrays.asList("1232151454963", "45646454545487"), smsContent));
        // 发送邮件
        rabbitTemplate.convertAndSend(MQConsumer.EXCHANGE_NAME0, "course.email", new EmailTo(Arrays.asList("12321@qq.com", "4564@qq.com"), emailContent));
        // 发送站内信
        rabbitTemplate.convertAndSend(MQConsumer.EXCHANGE_NAME0, "course.message", new MessageTo(Arrays.asList(1L, 2L), messageContent));
    }
}
